package com.koro.config;

import com.koro.filter.SecurityJwtFilter;
import com.koro.handler.SecurityAccessDeniedHandler;
import com.koro.handler.SecurityAuthenticationEntryPoint;
import com.koro.service.impl.LoginUsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

@Configuration
public class SecurityConfiguration {

    @Autowired
    private LoginUsersService usersService;
    @Resource
    private SecurityAccessDeniedHandler restfulAccessDeniedHandler;
    @Resource
    private SecurityAuthenticationEntryPoint restAuthenticationEntryPoint;


    @Bean
    public AuthenticationProvider authenticationProvider() {
        return new AuthenticationProvider() {
            @Override  //认证过程
            public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                String username = authentication.getName();
                String password = authentication.getCredentials().toString();
                UserDetails user = usersService.loadUserByUsername(username);
                if(passwordEncoder().matches(password,user.getPassword())) {
                    return new UsernamePasswordAuthenticationToken(user,password, user.getAuthorities());
                } else {
                    throw new BadCredentialsException("The username or password is wrong.");
                }
            }

            @Override
            public boolean supports(Class<?> authentication) {
                return authentication.equals(UsernamePasswordAuthenticationToken.class);
            }
        };
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf().disable()  // 关闭csrf
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)  // 不通过session获取SecurityContext
                .and()
                .authorizeRequests()
                .antMatchers("/login").anonymous()  // 允许登录接口匿名访问
                .antMatchers("/doc.html", "/webjars/**", "/v2/api-docs", "/swagger-resources/**").permitAll()
                .anyRequest().authenticated();  // 除上述之外的全部请求都需要鉴权认证
        //禁用缓存
        http.headers().cacheControl();
        //添加JWTFilter
        http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
        //添加自定义未授权和未登录结果返回
        http.exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthenticationEntryPoint);
        return http.build();
    }

    /**
     * JWT过滤器
     */
    @Bean
    public SecurityJwtFilter jwtFilter() {
        return new SecurityJwtFilter();
    }

    /**
     * 自定义加密器Bean
     * 强散列哈希加密实现,在Controller新增用户的时候用此bean生成密码，与及修改密码的时候用到此bean比较新旧密码是否匹配
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
